﻿using System;
using System.Collections.Generic;
using System.Linq.Expressions;
using System.Reflection;
using Microsoft.WindowsAzure.StorageClient;

namespace jp110311.StorageModels
{
    [CLSCompliant(false)]
    public class TableStoragePredicateUtility<T> where T: TableServiceEntity
    {
        private readonly MemberInfo _partitionKeyMember;
        private readonly MemberInfo _rowKeyMember;

        public TableStoragePredicateUtility()
        {
            _partitionKeyMember = typeof (T).GetProperty("PartitionKey");
            _rowKeyMember = typeof (T).GetProperty("RowKey");
        }

        public ParameterExpression GetParameter()
        {
            return Expression.Parameter(typeof (T));
        }

        public Expression GetPartitionKeyRef( Expression entity )
        {
            return Expression.MakeMemberAccess(entity, _partitionKeyMember);
        }

        public Expression GetRowKeyRef( Expression entity )
        {
            return Expression.MakeMemberAccess(entity, _rowKeyMember);
        }

        public Expression PartitionKeyEquals( Expression entity, string value)
        {
            return Expression.Equal(
                GetPartitionKeyRef(entity),
                Expression.Constant(value, typeof (string)));
        }

        public Expression RowKeyEquals( Expression entity, string value )
        {
            return Expression.Equal(
                GetRowKeyRef(entity),
                Expression.Constant(value, typeof (string)));
        }

        public Expression<Func<T, bool>> MakeLambda( Expression body, ParameterExpression param)
        {
            return Expression.Lambda<Func<T, bool>>(body, param);
        }

        public Expression<Func<T,bool>> BuildLambda( string partitionKey, IEnumerable<string> rowKeys )
        {
            ParameterExpression param = GetParameter();
            Expression predBody = null;
            foreach (var rowKey in rowKeys)
            {
                if (predBody == null)
                {
                    predBody = RowKeyEquals(param, rowKey);
                }
                else
                {
                    predBody = Expression.OrElse(
                        predBody,
                        RowKeyEquals(param, rowKey)
                        );
                }
            }
            if (predBody == null) return null;
            predBody = Expression.AndAlso(PartitionKeyEquals(param, partitionKey), predBody);
            return MakeLambda(predBody, param);
        }
    }
}